package org.etherframework.tests.features.dependency
{
	import org.etherframework.core.IModule;
	import org.etherframework.dependency.Dependency;
	import org.etherframework.dependency.IDependencies;
	import org.etherframework.tests.features.dependency.models.ComplexModel;
	import org.etherframework.tests.features.dependency.models.IInstanceModel2;
	import org.etherframework.tests.features.dependency.models.IInterfacedModel;
	import org.etherframework.tests.features.dependency.models.InstanceModel;
	import org.etherframework.tests.features.dependency.models.InstanceModel2;
	import org.etherframework.tests.features.dependency.models.InterfacedModel;
	import org.etherframework.tests.features.dependency.models.NoneExistentModel;
	import org.etherframework.tests.features.dependency.models.RecursiveModel;
	import org.etherframework.tests.features.dependency.models.SimpleModel;
	import org.etherframework.tests.features.dependency.models.SingletonModel;
	import org.etherframework.tests.utils.TestUtility;
	import org.hamcrest.assertThat;
	import org.hamcrest.object.instanceOf;
	import org.hamcrest.object.notNullValue;

	public class when_adding_dependencies
	{	
		private static var _testUtility:TestUtility = new TestUtility();
		private static var _module:IModule;
		private static var _d:IDependencies;
		
		private static var _simpleModel:SimpleModel;
		private static var _complexModel:ComplexModel;
		private static var _interfacedModel:InterfacedModel;
		private static var _singletonModel:SingletonModel;
		
		[BeforeClass]
		public static function setUpBeforeClass():void
		{
			_module = _testUtility.createModule();
			_d = _module.dependencies;
			_d.addClass(SimpleModel);
			_d.addClass(ComplexModel);
			_d.addClass(InterfacedModel, IInterfacedModel);
			_d.addSingleton(SingletonModel);
			_d.addInstance(new InstanceModel());
			_d.addInstance(new InstanceModel2(), IInstanceModel2);
		}
		
		[AfterClass]
		public static function tearDownAfterClass():void
		{
			_testUtility.dispose();
			SimpleModel.instanceCounter = 0;
			ComplexModel.instanceCounter = 0;
			InterfacedModel.instanceCounter = 0;
			SingletonModel.instanceCounter = 0;
			InstanceModel.instanceCounter = 0;
			InstanceModel2.instanceCounter = 0;
		}
		
		[Before]
		public function setUp():void
		{
		}
		
		[After]
		public function tearDown():void
		{
		}
		
		[Test(order=1)]
		public function dependencies_should_be_added():void
		{
			assertThat(_d.getDependency(SimpleModel), instanceOf(Dependency));
			assertThat(_d.getDependency(ComplexModel), instanceOf(Dependency));
			assertThat(_d.getDependency(IInterfacedModel), instanceOf(Dependency));
			assertThat(_d.getDependency(SingletonModel), instanceOf(Dependency));
			assertThat(_d.getDependency(InstanceModel), instanceOf(Dependency));
			assertThat(_d.getDependency(IInstanceModel2), instanceOf(Dependency));
		}
		
		[Test(order=2)]
		public function you_can_not_add_dependencies_with_incorrect_type():void
		{
			var err:Error;
			try {
				_d.addInstance(new Object(), IInstanceModel2);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addClass(RecursiveModel, IInterfacedModel);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addClass(RecursiveModel, ComplexModel);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addSingleton(RecursiveModel, IInterfacedModel);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addSingleton(RecursiveModel, SimpleModel);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addInstance(new NoneExistentModel(), ComplexModel);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addInstance(new NoneExistentModel(), IInterfacedModel);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
		}
		
		[Test(order=3)]
		public function you_can_not_add_dependencies_with_existing_types():void
		{
			var err:Error;
			try {
				_d.addInstance(new InstanceModel());
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addInstance(new InstanceModel2(), IInstanceModel2);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addClass(SingletonModel);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addSingleton(SingletonModel);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addSingleton(SimpleModel);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addClass(SimpleModel);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addInstance(new SimpleModel(null));
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addInstance(ComplexModel);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
		}
		
		[Test(order=4)]
		public function you_can_not_add_null_dependencies():void
		{
			var err:Error;
			try {
				_d.addInstance(null);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addClass(null);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
			
			err = null;
			try {
				_d.addSingleton(null);
			} catch (e:Error) { err = e;}
			assertThat(err, notNullValue());
		}
	}
}